<template>
  <div class="dept-chart-box">
    <el-empty class="nodata" v-if="!deptStats.length" />
    <div v-else>
      <div class="text-center" v-if="showSwipeTip">
        <div class="swipe-tip">← 左右滑动，查看更多数据 →</div>
      </div>
    </div>
    <div class="dept-chart" ref="container" />
  </div>
</template>
<script>
import * as echarts from 'echarts'
export default {
  name: 'DeptChart',
  props: {
    data: { type: Array, default: () => [] },
    // is project dimension
    isPrjDim: { type: Boolean, default: false }
  },
  data() {
    return {
      deptStats: [],
      showSwipeTip: false
    }
  },
  watch: {
    data: {
      deep: true,
      handler() {
        this.init()
      }
    }
  },
  methods: {
    init() {
      // const isPrjDim = this.isPrjDim
      const container = this.$refs.container
      const ctx = echarts.getInstanceByDom(container) || echarts.init(container)
      const { deptStats, averagePassRate } = this.handleDeptStats()
      this.deptStats = deptStats
      this.showSwipeTip = false

      if (!deptStats.length) {
        ctx.clear()
        this.ctx = ctx
        return
      }

      // 离容器上、左、右、下侧的距离
      const left = 56
      const right = 10
      // const bottom = isPrjDim ? 50 : 75
      const bottom = 50
      const cellHeight = 25 // 单元格高度
      const rowNum = bottom / cellHeight // 行数
      const lineColor = '#dcdfe6'

      const excRate = []
      const validRate = []
      const unvalidRate = []
      const xa = []
      const ya = []
      const ya1 = []
      const numArr = [] // 各项数量数组，用于 tooltip
      deptStats.map(i => {
        excRate.push(i.excRate || null)
        validRate.push(i.validRate || null)
        unvalidRate.push(i.unvalidRate || null)
        xa.push(i.name)
        ya.push(i.ciNum)
        ya1.push(i.taskNum)
        numArr.push([i.excNum, i.valNum, i.unValNum])
      })

      // 横线
      function getTableLine(num) {
        const list = []
        for (let i = 1; i <= num; i++) {
          list.push({
            type: 'line',
            bottom: bottom - i * cellHeight,
            right,
            style: { fill: '#fff', stroke: lineColor },
            shape: { x1: 0, y1: 0, x2: 9999, y2: 0 }
          })
        }
        return list
      }
      const graphic = getTableLine(rowNum)
      // 顶部的平均合格率；底部表格的左侧竖线
      graphic.push(
        { type: 'text', right: 10, top: 35, style: { text: `● 平均合格率：${averagePassRate}%`, fill: '#c9151e', font: '12px Helvetica' } },
        { type: 'line', bottom: 0, left: 0, style: { fill: '#fff', stroke: lineColor }, shape: { x1: 0, y1: cellHeight, x2: 0, y2: bottom } }
      )
      // 左侧文字。项目维度时不展示检查标段
      /*
      if (isPrjDim) {
        graphic.push({ type: 'text', left: 5, bottom: 2, style: { text: '检查项数\n量/个', fill: '#333', font: '10px Helvetica' } })
      } else {
        graphic.push(
          { type: 'text', left: 5, bottom: 27, style: { text: '检查项数\n量/个', fill: '#333', font: '10px Helvetica' } },
          { type: 'text', left: 5, bottom: 2, style: { text: '检查标段\n数量/个', fill: '#333', font: '10px Helvetica' } }
        )
      }
      */
      graphic.push({ type: 'text', left: 4, bottom: 6, style: { text: '检查项数', fill: '#333', font: '12px Helvetica' } })

      const chartWidth = container.clientWidth - left - right
      const barWidth = 80
      // 计算显示的柱子个数，至少4个
      const barNum = Math.max(Math.floor(chartWidth / barWidth), 4)
      // 实际显示的柱子数
      const actualBarNum = Math.min(barNum, deptStats.length)
      // 列宽
      const columnWidth = Math.floor(chartWidth / actualBarNum)

      const stackBar = {
        type: 'bar',
        stack: 'rate',
        barWidth: 40,
        label: {
          show: true,
          position: 'inside',
          formatter: '{c}%',
          fontSize: 11,
          fontWeight: 'bold',
          color: 'white',
          textBorderColor: 'inherit',
          textBorderWidth: 2
        }
      }
      // 标线
      const markLine = {
        data: [{ yAxis: averagePassRate }],
        silent: true,
        symbol: ['none', 'circle'],
        symbolSize: 5,
        lineStyle: { color: '#f00' },
        label: {
          distance: [-10, 5],
          formatter: '合格率',
          position: 'insideEndBottom',
          color: '#c9151e',
          fontSize: 8
        }
      }
      const series = [
        { ...stackBar, name: '优秀率', color: '#569cdc', data: excRate },
        { ...stackBar, name: '合格率', color: '#3bb375', data: validRate, markLine },
        { ...stackBar, name: '不合格率', color: '#c9151e', data: unvalidRate }
      ]
      const option = {
        tooltip: {
          trigger: 'axis',
          axisPointer: { type: 'shadow' },
          extraCssText: 'z-index: 2',
          formatter: params => {
            const indexNum = params[0].dataIndex || 0
            const numData = numArr[indexNum]
            let str = `<div>${params[0].axisValue}</div>`
            // 非项目维度时，展示“检查标段”
            /*
            if (!isPrjDim) {
              str += `<div>
              <span style="display:inline-block;margin-right:4px;border-radius:10px;width:10px;height:10px;background-color:#ea7ccc;"></span>
              <span>检查标段</span>:
              <span style="float:right;margin-left:20px;font-weight:900">${ya1[indexNum]} 个</span>
              </div>`
            }
            */
            params.map((i, index) => {
              str += `<div>
              <span>${i.marker}</span>
              <span>${i.seriesName.replace('率', '数量')}</span>:
              <span style="float:right;margin-left:20px;font-weight:900">${numData[index]} 个</span>
              </div>`
            })
            return str
          }
        },
        legend: { data: series },
        grid: { left, right, bottom },
        xAxis: {
          data: xa,
          axisLine: { lineStyle: { color: lineColor } },
          // 竖线长度
          axisTick: { length: bottom, lineStyle: { color: lineColor } },
          axisLabel: {
            interval: 0,
            margin: 0,
            width: columnWidth,
            overflow: 'truncate',
            formatter: (value, index) => {
              const indexNum = xa.findIndex(i => i === value) || 0
              return `{table|${value}}\n{table|${ya[indexNum]}个}`
              // if (isPrjDim) return `{table|${value}}\n{table|${ya[indexNum]}}`
              // return `{table|${value}}\n{table|${ya[indexNum]}}\n{table|${ya1[indexNum]}}`
            },
            rich: { table: { color: '#333', height: cellHeight, align: 'center', verticalAlign: 'middle' } }
          }
        },
        yAxis: {
          type: 'value',
          splitLine: { lineStyle: { type: 'dashed' } }
        },
        dataZoom: [
          {
            type: 'inside',
            rangeMode: ['value', 'value'],
            startValue: 0,
            endValue: barNum - 1, // endValue 为 0 时显示 1 个
            filterMode: 'none',
            zoomLock: true
          }
        ],
        series,
        graphic
      }
      ctx.clear()
      ctx.setOption(option)

      // 点击柱子或其周围
      ctx.getZr().off('click')
      ctx.getZr().on('click', param => {
        // 判断点击区域在 grid
        const pointInPixel = [param.offsetX, param.offsetY]
        if (!ctx.containPixel('grid', pointInPixel)) return
        // 所在x轴的索引
        const xIndex = ctx.convertFromPixel({ seriesIndex: 0 }, pointInPixel)[0]
        const item = deptStats[xIndex]
        // 没数据时（检查项数为0）不可穿透
        if (!item.ciNum) return
        this.$emit('barClick', item)
      })

      this.ctx = ctx

      // 显示的柱体个数少于数据个数时，显示左右滑动提示
      this.showSwipeTip = barNum < deptStats.length
    },
    resize() {
      this.ctx?.resize()
      this.init()
    },
    handleDeptStats() {
      const data = JSON.parse(JSON.stringify(this.data || []))
      if (!data.length) return { deptStats: [], averagePassRate: 0 }

      let passNumAll = 0
      let totalAll = 0

      data.map(i => {
        const excNum = i.excNum || 0
        // 合格包含优秀，需减掉
        const passNum = i.valNum || 0
        const valNum = +(passNum - excNum).toFixed(2)
        const unValNum = i.unValNum || 0
        const total = i.ciNum || 0
        // 计算百分比
        const excRate = total ? +((excNum / total) * 100).toFixed(2) : 0
        let validRate = total ? +((valNum / total) * 100).toFixed(2) : 0
        // 保证和小于100。当小数第三位都是5时，toFixed(2) 后会出现和大于100，如 excNum=27,valNum=5,total=32 时
        if ((excRate + validRate).toFixed(2) > 100) validRate = +(100 - excRate).toFixed(2)
        const unvalidRate = total ? +(100 - excRate - validRate).toFixed(2) : 0

        passNumAll += passNum
        totalAll += total

        i.excNum = excNum
        i.valNum = valNum
        i.unValNum = unValNum
        i.ciNum = total
        i.excRate = excRate
        i.validRate = validRate
        i.unvalidRate = unvalidRate
        i.taskNum = i.taskNum || 0
      })

      // 平均合格率
      const averagePassRate = totalAll ? +((passNumAll / totalAll) * 100).toFixed(2) : 0

      return { deptStats: data, averagePassRate }
    }
  }
}
</script>
<style lang="scss" scoped>
.dept-chart-box {
  position: relative;
}
.nodata {
  position: absolute;
  left: 50%;
  margin-left: -80px;
}
.swipe-tip {
  display: inline-block;
  padding: 6px 40px;
  font-size: 12px;
  zoom: 0.95;
  background-image: linear-gradient(to right, rgba(#f2f2f2, 0), #f2f2f2 20%, #f2f2f2 80%, rgba(#f2f2f2, 0));
  margin-bottom: 15px;
}
.dept-chart {
  width: 100%;
  height: 400px;
  overflow: hidden;
}
</style>
